package com.hup.utils.jna.hotkey;

import lombok.Getter;
import lombok.Setter;

import javax.swing.*;
import java.awt.event.KeyEvent;
import java.util.Objects;

/**
 * 热键对象类
 */
public class HotKey {
    public final boolean ctrl;
    public final boolean shift;
    public final boolean alt;
    public final Integer keyCode;
    public final String keyText;
    public final KeyType type;
    private final HotKeyAction action;

    /**
     * 重复激活快捷键回调的最小间隔ms (少于间隔的事件将被忽略)
     */
    @Setter
    private int minActSpan = 500;
    /**
     * 上次开始执行action的时间
     */
    @Getter
    private Long lastActTime;

    public HotKey(boolean ctrl, boolean shift, boolean alt, HotKeyAction action) {
        this(ctrl, shift, alt, null, action);
    }

    /**
     * @param keyCode 不能是前面三个[功能键],代码不做校验
     * @param action notNull
     */
    public HotKey(boolean ctrl, boolean shift, boolean alt, Integer keyCode, HotKeyAction action) {
        this.ctrl = ctrl;
        this.shift = shift;
        this.alt = alt;
        int funcCount = funcCount();
        if (funcCount < 2) {
            throw new IllegalArgumentException("[功能键]必须≥2个");
        }
        this.keyCode = keyCode;
        keyText = keyCode != null ? KeyEvent.getKeyText(keyCode): null;
        if (keyCode == null) {
            type = funcCount == 3 ? KeyType.F3 : KeyType.F2;
        } else {
            type = funcCount == 3 ? KeyType.F3_K : KeyType.F2_K;
        }
        this.action = action;
    }

    private int funcCount() {
        int count = 0;
        if (ctrl) count++;
        if (shift) count++;
        if (alt) count++;
        return count;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("[");
        if (ctrl) sb.append("ctrl+");
        if (shift) sb.append("shift+");
        if (alt) sb.append("alt+");
        if (keyText != null) {
            sb.append(keyText);
        } else {
            sb.delete(sb.length() - 1, sb.length());
        }
        sb.append(']');
        return sb.toString();
    }

    /**
     * 判断是否与目标热键有冲突;
     * <pre>
     * F3与之冲突的
     *   1.1 F3: 本身
     *   1.2 F3_K: 触发这个热键前,肯定先触发F3
     *   1.3 F2: 要触发F3前,肯定先这个热键
     * F3_K与之冲突的
     *   2.1 F3_K: 本身
     *   2.2 F2: 要触发F3_K前,肯定先这个热键
     *   2.3 F2_K: key一样时, 要触发F3_K前,肯定先这个热键
     * F2与之冲突的
     *   3.1 F2: 本身
     *   3.2 F2_K: (两个功能键一样时)触发这个热键前,肯定先触发F2
     * F2_K与之冲突的
     *   4.1 F2_K: 本身
     * </pre>
     */
    @SuppressWarnings("SimplifiableIfStatement")
    protected boolean isConflict(HotKey hotKey) {
        if (ctrl == hotKey.ctrl && shift == hotKey.shift && alt == hotKey.alt && Objects.equals(keyCode, hotKey.keyCode)) {
            //[1,2,3,4].1
            return true;
        }
        if (type == KeyType.F3 || hotKey.type == KeyType.F3) {
            //这里肯定 仅有一个F3(前面排除两个一样的)
            HotKey other = type == KeyType.F3 ? hotKey : this;
            //1.2,1.3
            return other.type == KeyType.F3_K || other.type == KeyType.F2;
        }
        if (type == KeyType.F3_K || hotKey.type == KeyType.F3_K) {
            //至少是: 一个F3_K或两个不一样的F3_K
            HotKey f3k = type == KeyType.F3_K ? this : hotKey;
            HotKey other = type == KeyType.F3_K ? hotKey : this;
            if (other.type == KeyType.F2) {
                return true;//2.2
            } else if (other.type == KeyType.F2_K) {
                //2.3
                return f3k.keyCode.equals(other.keyCode);
            } else {
                return false;
            }
        }
        if (type == KeyType.F2 || hotKey.type == KeyType.F2) {
            HotKey f2 = type == KeyType.F2 ? this : hotKey;
            HotKey other = type == KeyType.F2 ? hotKey : this;
            if (other.type == KeyType.F2_K) {
                int sameFunc = 0;
                if (f2.ctrl == other.ctrl) sameFunc++;
                if (f2.shift == other.shift) sameFunc++;
                if (f2.alt == other.alt) sameFunc++;
                return sameFunc >= 2;//3.2
            } else {
                return false;
            }
        }

        return false;
    }

    protected boolean ignoreAction() {
        long cur = System.currentTimeMillis();
        return lastActTime != null && cur - lastActTime < minActSpan;
    }

    protected void doActive() {
        //时间必须在执行前就刷新,防止action耗时任务进行中时,又触发新的回调
        lastActTime = System.currentTimeMillis();
        SwingUtilities.invokeLater(() -> {
            //异常不会影响热键监听线程,不用catch
            action.onPressed(this);
        });
    }

    /**
     * 热键种类
     */
    private enum KeyType {
        //3键
        F3,
        //3键+key
        F3_K,
        //2键
        F2,
        //2键+key
        F2_K
    }

    public interface HotKeyAction {
        /**
         * 按下按键后,[在AWT线程]激活的回调;
         * @apiNote 仅在热键完全一致时才触发:如用户按下F3+key,注册的是F2+key,就不触发
         */
        void onPressed(HotKey hotKey);
    }
}